Bug 318807 – Offscreen windows and window redirection.
author10:49:20 Tim Janik <timj@imendio.com>
Wed, 21 May 2008 19:04:24 +0000 (19:04 +0000)
committerTim Janik <timj@src.gnome.org>
Wed, 21 May 2008 19:04:24 +0000 (19:04 +0000)
2008-03-18 10:49:20  Tim Janik  <timj@imendio.com>

* Applied pixmap redirection patch by Alexander Larsson with
various updates from:
Bug 318807 – Offscreen windows and window redirection.

Updates:

* updated docs to mention "Since 2.16".

* tests/testgtk.c: fixed snapshooting pixmap leak.
convert pixmap to pixbuf after snapshooting, to compensate for different
bit depths (occurs when snapshooting ARGB visuals and displaying the
pixmap in an RGB visual).

* gdk/gdkwindow.[hc]: made GdkWindowRedirect private.

* gdk/gdkwindow.c: removed damage idle handler, there's no aparent
need for it. enqueue damage notification as GDK_DAMAGE events
for each painting redirection at the start of the event queue.
consider windows with a redirection fully visible when invalidating,
and when updating from backing store. cleaned up stale variables.

* gdk/gdkevents.c: added _gdk_event_queue_prepend().

* gtk/gtkwidget.c: fixed coordinates for !NO_WINDOW widgets in
gtk_widget_get_snapshot; this fixes garbage snap offsets for gammacurve,
tree, drawingarea, text, handlebox, etc.
clip the redirected window hierarchy to window sizes, the visible
rectangles don't need to be taken into account here.
extended snapshooting docs to recommend gdk_pixbuf_get_from_drawable()
in case pixmap visuals could mismatch.

* gdk/x11/gdkwindow-x11.c: removed _gdk_windowing_window_get_visible_rect().

Base patch:

* tests/testgtk.c: add a "Snapshot" test to demonstrate snapshooting
of possibly obscured widgets into an offscreen pixmap.

* gtk/gtkwidget.[hc]: add GtkWidget::damage-event signal, add
gtk_widget_get_snapshot() to render a widget's contents to a GdkPixmap.

* gtk/gtkmain.c: dispatch GDK_DAMAGE events.

* gdk/gdkwindow.c: moved outer gdk_window_new() and gdk_window_reparent()
implementations here, adapted them to propagate redirects to child windows.
gdk_window_end_paint(): copy repainted window contents to redirection pixmap,
clipped to visible region. queue GDK_DAMAGE event delivery.
gdk_window_redirect_to_drawable(): install window painting redirection.
gdk_window_remove_redirection(): remove previously installed redirection.

* gdk/x11/gdkwindow-x11.c: added _gdk_windowing_window_get_visible_rect(),
renamed _gdk_window_new() and _gdk_window_reparent().

* gdk/gdkwindow.h: added GdkWindowRedirect* to GdkWindowObject, export
gdk_window_redirect_to_drawable() and gdk_window_remove_redirection().

* gdk/gdkevents.h: added GDK_DAMAGE event type.

* gdk/gdkevents.c: extract time and state from GDK_DAMAGE events.

* gdk/gdkinternals.h: added internal prototypes.

svn path=/trunk/; revision=20122

12 files changed:
ChangeLog
gdk/gdk.symbols
gdk/gdkevents.c
gdk/gdkevents.h
gdk/gdkinternals.h
gdk/gdkwindow.c
gdk/gdkwindow.h
gdk/x11/gdkwindow-x11.c
gtk/gtkmain.c
gtk/gtkwidget.c
gtk/gtkwidget.h
tests/testgtk.c

index bd914a3fadd3da9b8047667bad553215fa07330e..bd181cfce339c9c1e565c32cf0887a54d5ad1614 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,69 @@
+2008-03-18 10:49:20  Tim Janik  <timj@imendio.com>
+
+       * Applied pixmap redirection patch by Alexander Larsson with
+       various updates from:
+       Bug 318807 – Offscreen windows and window redirection.
+
+
+       Updates:
+
+       * updated docs to mention "Since 2.16".
+
+       * tests/testgtk.c: fixed snapshooting pixmap leak.
+       convert pixmap to pixbuf after snapshooting, to compensate for different
+       bit depths (occurs when snapshooting ARGB visuals and displaying the
+       pixmap in an RGB visual).
+
+       * gdk/gdkwindow.[hc]: made GdkWindowRedirect private.
+
+       * gdk/gdkwindow.c: removed damage idle handler, there's no aparent
+       need for it. enqueue damage notification as GDK_DAMAGE events
+       for each painting redirection at the start of the event queue.
+       consider windows with a redirection fully visible when invalidating,
+       and when updating from backing store. cleaned up stale variables.
+
+       * gdk/gdkevents.c: added _gdk_event_queue_prepend().
+
+       * gtk/gtkwidget.c: fixed coordinates for !NO_WINDOW widgets in
+       gtk_widget_get_snapshot; this fixes garbage snap offsets for gammacurve,
+       tree, drawingarea, text, handlebox, etc.
+       clip the redirected window hierarchy to window sizes, the visible
+       rectangles don't need to be taken into account here.
+       extended snapshooting docs to recommend gdk_pixbuf_get_from_drawable()
+       in case pixmap visuals could mismatch.
+
+       * gdk/x11/gdkwindow-x11.c: removed _gdk_windowing_window_get_visible_rect().
+
+
+       Base patch:
+
+       * tests/testgtk.c: add a "Snapshot" test to demonstrate snapshooting
+       of possibly obscured widgets into an offscreen pixmap.
+
+       * gtk/gtkwidget.[hc]: add GtkWidget::damage-event signal, add
+       gtk_widget_get_snapshot() to render a widget's contents to a GdkPixmap.
+
+       * gtk/gtkmain.c: dispatch GDK_DAMAGE events.
+
+       * gdk/gdkwindow.c: moved outer gdk_window_new() and gdk_window_reparent()
+       implementations here, adapted them to propagate redirects to child windows.
+       gdk_window_end_paint(): copy repainted window contents to redirection pixmap,
+       clipped to visible region. queue GDK_DAMAGE event delivery.
+       gdk_window_redirect_to_drawable(): install window painting redirection.
+       gdk_window_remove_redirection(): remove previously installed redirection.
+
+       * gdk/x11/gdkwindow-x11.c: added _gdk_windowing_window_get_visible_rect(),
+       renamed _gdk_window_new() and _gdk_window_reparent().
+
+       * gdk/gdkwindow.h: added GdkWindowRedirect* to GdkWindowObject, export
+       gdk_window_redirect_to_drawable() and gdk_window_remove_redirection().
+
+       * gdk/gdkevents.h: added GDK_DAMAGE event type.
+
+       * gdk/gdkevents.c: extract time and state from GDK_DAMAGE events.
+
+       * gdk/gdkinternals.h: added internal prototypes.
+
 2008-05-21  Michael Natterer  <mitch@imendio.com>
 
        * gtk/gtkalignment.c
index 9f81c6c3ad96b1f3dcd4e0c07bea43973c6fc2e6..fd12d472a053394a2a36b79398d4a4c319d3a9f2 100644 (file)
@@ -646,6 +646,8 @@ gdk_window_impl_x11_get_type G_GNUC_CONST
 #if IN_HEADER(__GDK_WINDOW_H__)
 #if IN_FILE(__GDK_WINDOW_C__)
 gdk_get_default_root_window
+gdk_window_new
+gdk_window_reparent
 gdk_window_add_filter
 gdk_window_at_pointer
 gdk_window_begin_paint_rect
@@ -703,7 +705,6 @@ gdk_window_move_region
 
 #if IN_HEADER(__GDK_WINDOW_H__)
 #if IN_FILE(__GDK_WINDOW_X11_C__)
-gdk_window_new
 gdk_window_foreign_new_for_display
 gdk_window_lookup
 gdk_window_lookup_for_display
@@ -714,7 +715,6 @@ gdk_window_withdraw
 gdk_window_move
 gdk_window_resize
 gdk_window_move_resize
-gdk_window_reparent
 gdk_window_raise
 gdk_window_lower
 gdk_window_focus
index 8b24f0bac2420c44718605be5308d544fe78c1d2..bc0e62a42d6f8dd949772eebef6aa0938e0b8bb1 100644 (file)
@@ -78,6 +78,25 @@ _gdk_event_queue_find_first (GdkDisplay *display)
   return NULL;
 }
 
+/**
+ * _gdk_event_queue_prepend:
+ * @display: a #GdkDisplay
+ * @event: Event to prepend.
+ *
+ * Prepends an event before the head of the event queue.
+ *
+ * Returns: the newly prepended list node.
+ **/
+GList*
+_gdk_event_queue_prepend (GdkDisplay *display,
+                         GdkEvent   *event)
+{
+  display->queued_events = g_list_prepend (display->queued_events, event);
+  if (!display->queued_tail)
+    display->queued_tail = display->queued_events;
+  return display->queued_events;
+}
+
 /**
  * _gdk_event_queue_append:
  * @display: a #GdkDisplay
@@ -546,6 +565,7 @@ gdk_event_get_time (const GdkEvent *event)
       case GDK_CONFIGURE:
       case GDK_FOCUS_CHANGE:
       case GDK_NOTHING:
+      case GDK_DAMAGE:
       case GDK_DELETE:
       case GDK_DESTROY:
       case GDK_EXPOSE:
@@ -616,6 +636,7 @@ gdk_event_get_state (const GdkEvent        *event,
       case GDK_SELECTION_NOTIFY:
       case GDK_PROXIMITY_IN:
       case GDK_PROXIMITY_OUT:
+      case GDK_DAMAGE:
       case GDK_DRAG_ENTER:
       case GDK_DRAG_LEAVE:
       case GDK_DRAG_MOTION:
index 809992cf705f30abc6585dbd01a7769d9ec30e1e..ba2c82ac8f5945515508e10072ce79ce07bd791f 100644 (file)
@@ -146,7 +146,8 @@ typedef enum
   GDK_WINDOW_STATE      = 32,
   GDK_SETTING           = 33,
   GDK_OWNER_CHANGE      = 34,
-  GDK_GRAB_BROKEN       = 35
+  GDK_GRAB_BROKEN       = 35,
+  GDK_DAMAGE            = 36
 } GdkEventType;
 
 /* Event masks. (Used to select what types of events a window
index 420f8bd46295a89342fc8bec4ca3d0243adcd44c..b5ce96e50e1ab139c4d33932c8ae6cec5f3cd196 100644 (file)
@@ -184,6 +184,8 @@ GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
 GList* _gdk_event_queue_find_first  (GdkDisplay *display);
 void   _gdk_event_queue_remove_link (GdkDisplay *display,
                                     GList      *node);
+GList*  _gdk_event_queue_prepend    (GdkDisplay *display,
+                                    GdkEvent   *event);
 GList*  _gdk_event_queue_append     (GdkDisplay *display,
                                     GdkEvent   *event);
 void _gdk_event_button_generate     (GdkDisplay *display,
@@ -310,6 +312,14 @@ GdkWindow* _gdk_windowing_window_at_pointer  (GdkDisplay       *display,
 gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
                                        gint        depth);
 
+GdkWindow* _gdk_window_new                        (GdkWindow     *parent,
+                                                  GdkWindowAttr *attributes,
+                                                  gint           attributes_mask);
+void       _gdk_window_reparent                   (GdkWindow     *window,
+                                                  GdkWindow     *new_parent,
+                                                  gint           x,
+                                                  gint           y);
+
 #define GDK_WINDOW_IS_MAPPED(window) ((((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0)
 
 /* Called before processing updates for a window. This gives the windowing
index 323450aa50567b9d79cf614048fb7feef9f7416d..966e0b68993199f1782f1b2fda2f56976fcec3d8 100644 (file)
@@ -47,6 +47,26 @@ struct _GdkWindowPaint
   cairo_surface_t *surface;
 };
 
+typedef struct {
+  GdkRegion *old_region;
+  gint old_clip_x_origin;
+  gint old_clip_y_origin;
+  gint x_offset;
+  gint y_offset;
+} GdkWindowClipData;
+
+struct _GdkWindowRedirect
+{
+  GdkWindowObject *redirected;
+  GdkDrawable *pixmap;
+  gint src_x;
+  gint src_y;
+  gint dest_x;
+  gint dest_y;
+  gint width;
+  gint height;
+};
+
 static GdkGC *gdk_window_create_gc      (GdkDrawable     *drawable,
                                          GdkGCValues     *values,
                                          GdkGCValuesMask  mask);
@@ -191,6 +211,23 @@ static void gdk_window_clear_backing_rect (GdkWindow *window,
                                           gint       y,
                                           gint       width,
                                           gint       height);
+static void setup_redirect_clip           (GdkWindow         *window,
+                                          GdkGC             *gc,
+                                          GdkWindowClipData *data);
+static void reset_redirect_clip           (GdkWindow         *offscreen,
+                                          GdkGC             *gc,
+                                          GdkWindowClipData *data);
+static void gdk_window_redirect_free      (GdkWindowRedirect *redirect);
+static void apply_redirect_to_children    (GdkWindowObject   *private,
+                                          GdkWindowRedirect *redirect);
+static void remove_redirect_from_children (GdkWindowObject   *private,
+                                          GdkWindowRedirect *redirect);
+static GdkRegion *_gdk_window_calculate_full_clip_region (GdkWindow *window,
+                                                         GdkWindow *base_window,
+                                                         GdkGC *gc,
+                                                         gboolean do_children,
+                                                         gint *base_x_offset,
+                                                         gint *base_y_offset);
 
 static gpointer parent_class = NULL;
 
@@ -311,6 +348,91 @@ gdk_window_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+/**
+ * gdk_window_new:
+ * @parent: a #GdkWindow, or %NULL to create the window as a child of
+ *   the default root window for the default display.
+ * @attributes: attributes of the new window
+ * @attributes_mask: mask indicating which fields in @attributes are valid
+ * 
+ * Creates a new #GdkWindow using the attributes from
+ * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
+ * more details.  Note: to use this on displays other than the default
+ * display, @parent must be specified.
+ * 
+ * Return value: the new #GdkWindow
+ **/
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+               GdkWindowAttr *attributes,
+               gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowObject *private, *parent_private;
+  
+  g_return_val_if_fail (attributes != NULL, NULL);
+
+  window = _gdk_window_new (parent, attributes, attributes_mask);
+
+  /* Inherit redirection from parent */
+  if (parent != NULL)
+    {
+      parent_private = GDK_WINDOW_OBJECT (parent);
+      private = GDK_WINDOW_OBJECT (window);
+      private->redirect = parent_private->redirect;
+    }
+  
+  return window;
+}
+
+/**
+ * gdk_window_reparent:
+ * @window: a #GdkWindow
+ * @new_parent: new parent to move @window into
+ * @x: X location inside the new parent
+ * @y: Y location inside the new parent
+ *
+ * Reparents @window into the given @new_parent. The window being
+ * reparented will be unmapped as a side effect.
+ * 
+ **/
+void
+gdk_window_reparent (GdkWindow *window,
+                    GdkWindow *new_parent,
+                    gint       x,
+                    gint       y)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  if (GDK_WINDOW_DESTROYED (window) ||
+      (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
+    {
+      return;
+    }
+
+  private = (GdkWindowObject *) window;
+
+  /* Break up redirection if inherited */
+  if (private->redirect && private->redirect->redirected != private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      private->redirect = NULL;
+    }
+  
+  _gdk_window_reparent (window, new_parent, x, y);
+
+  /* Inherit parent redirect if we don't have our own */
+  if (private->parent && private->redirect == NULL)
+    {
+      private->redirect = private->parent->redirect;
+      apply_redirect_to_children (private, private->redirect);
+    }
+}
+
 static void
 window_remove_filters (GdkWindow *window)
 {
@@ -446,6 +568,11 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
          window_remove_filters (window);
 
           gdk_drawable_set_colormap (GDK_DRAWABLE (window), NULL);
+
+         /* If we own the redirect, free it */
+         if (private->redirect && private->redirect->redirected == private)
+           gdk_window_redirect_free (private->redirect);
+         private->redirect = NULL;
        }
       break;
     }
@@ -1089,6 +1216,20 @@ gdk_window_end_paint (GdkWindow *window)
                      clip_box.x - x_offset, clip_box.y - y_offset,
                      clip_box.width, clip_box.height);
 
+  if (private->redirect)
+    {
+      GdkWindowClipData data;
+      
+      setup_redirect_clip (window, tmp_gc, &data);
+      gdk_draw_drawable (private->redirect->pixmap, tmp_gc, paint->pixmap,
+                        clip_box.x - paint->x_offset,
+                        clip_box.y - paint->y_offset,
+                        clip_box.x + data.x_offset,
+                        clip_box.y + data.y_offset,
+                        clip_box.width, clip_box.height);
+      reset_redirect_clip (window, tmp_gc, &data);
+    }
+  
   /* Reset clip region of the cached GdkGC */
   gdk_gc_set_clip_region (tmp_gc, NULL);
 
@@ -1946,6 +2087,65 @@ gdk_window_clear_backing_rect (GdkWindow *window,
 #endif
 }
 
+static void
+gdk_window_clear_backing_rect_redirect (GdkWindow *window,
+                                       gint       x,
+                                       gint       y,
+                                       gint       width,
+                                       gint       height)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkWindowRedirect *redirect = private->redirect;
+  GdkRegion *clip_region;
+  gint x_offset, y_offset;
+  BackingRectMethod method;
+  GdkWindowPaint paint;
+  
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  paint.x_offset = x_offset;
+  paint.y_offset = y_offset;
+  paint.pixmap = redirect->pixmap;
+  paint.surface = _gdk_drawable_ref_cairo_surface (redirect->pixmap);
+  
+  clip_region = _gdk_window_calculate_full_clip_region (window,
+                                                       GDK_WINDOW (redirect->redirected),
+                                                       NULL, TRUE,
+                                                       &x_offset, &y_offset);
+  
+
+  method.cr = NULL;
+  method.gc = NULL;
+  setup_backing_rect_method (&method, window, &paint, 0, 0);
+
+  if (method.cr)
+    {
+      g_assert (method.gc == NULL);
+
+      cairo_rectangle (method.cr, x, y, width, height);
+      cairo_clip (method.cr);
+
+      gdk_cairo_region (method.cr, clip_region);
+      cairo_fill (method.cr);
+
+      cairo_destroy (method.cr);
+    }
+  else
+    {
+      g_assert (method.gc != NULL);
+
+      gdk_gc_set_clip_region (method.gc, clip_region);
+      gdk_draw_rectangle (window, method.gc, TRUE, x, y, width, height);
+      g_object_unref (method.gc);
+
+    }
+
+  gdk_region_destroy (clip_region);
+  cairo_surface_destroy (paint.surface);
+}
+
+
 /**
  * gdk_window_clear:
  * @window: a #GdkWindow
@@ -1992,7 +2192,12 @@ gdk_window_clear_area (GdkWindow *window,
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
   else
-    _gdk_windowing_window_clear_area (window, x, y, width, height);
+    {
+      if (private->redirect)
+       gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+       
+      _gdk_windowing_window_clear_area (window, x, y, width, height);
+    }
 }
 
 /**
@@ -2025,6 +2230,9 @@ gdk_window_clear_area_e (GdkWindow *window,
   if (private->paint_stack)
     gdk_window_clear_backing_rect (window, x, y, width, height);
 
+  if (private->redirect)
+    gdk_window_clear_backing_rect_redirect (window, x, y, width, height);
+  
   _gdk_windowing_window_clear_area_e (window, x, y, width, height);
 }
 
@@ -2629,7 +2837,18 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
       return;
     }
 
-  visible_region = gdk_drawable_get_visible_region (window);
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    {
+      GdkRectangle visible_rect = { 0, 0, 0, 0 };
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &visible_rect.width, &visible_rect.height);
+      visible_region = gdk_region_rectangle (&visible_rect);
+    }
+  else
+    visible_region = gdk_drawable_get_visible_region (window);
   gdk_region_intersect (visible_region, region);
 
   tmp_list = private->children;
@@ -2678,7 +2897,7 @@ gdk_window_invalidate_maybe_recurse (GdkWindow       *window,
     {
       if (debug_updates)
         draw_ugly_color (window, region);
-      
+
       if (private->update_area)
        {
          gdk_region_union (private->update_area, visible_region);
@@ -3223,5 +3442,348 @@ gdk_window_set_composited (GdkWindow *window,
   private->composited = composited;
 }
 
+
+static void
+remove_redirect_from_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (child->redirect == redirect)
+       {
+         child->redirect = NULL;
+         remove_redirect_from_children (child, redirect);
+       }
+    }
+}
+
+/**
+ * gdk_window_remove_redirection:
+ * @window: a #GdkWindow
+ *
+ * Removes and active redirection started by
+ * gdk_window_redirect_to_drawable().
+ **/
+void
+gdk_window_remove_redirection (GdkWindow *window)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect &&
+      private->redirect->redirected == private)
+    {
+      remove_redirect_from_children (private, private->redirect);
+      gdk_window_redirect_free (private->redirect);
+      private->redirect = NULL;
+    }
+}
+
+static void
+apply_redirect_to_children (GdkWindowObject *private, GdkWindowRedirect *redirect)
+{
+  GList *l;
+  GdkWindowObject *child;
+
+  for (l = private->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+
+      /* Don't redirect this child if it already has another redirect */
+      if (!child->redirect)
+       {
+         child->redirect = redirect;
+         apply_redirect_to_children (child, redirect);
+       }
+    }
+}
+
+/**
+ * gdk_window_redirect_to_drawable:
+ * @window: a #GdkWindow
+ * @drawable: a #GdkDrawable
+ * src_x: x position in @window
+ * src_y: y position in @window
+ * dest_x: x position in @drawable
+ * dest_y: y position in @drawable
+ * width: width of redirection
+ * height: height of redirection
+ *
+ * Redirects drawing into @windows so that drawing to the
+ * window in the rectangle specified by @src_x, @src_y,
+ * @width and @height is also drawn into @drawable at
+ * @dest_x, @dest_y.
+ *
+ * Only drawing between gdk_window_begin_paint_region() and
+ * gdk_window_end_paint() is redirected.
+ *
+ * Redirection is active until gdk_window_remove_redirection()
+ * is called.
+ *
+ * This function should not be used on windows created by
+ * gdk_window_new_offscreen(), as that is implemented using
+ * redirection.
+ **/
+void
+gdk_window_redirect_to_drawable (GdkWindow *window,
+                                GdkDrawable *drawable,
+                                gint src_x, gint src_y,
+                                gint dest_x, gint dest_y,
+                                gint width, gint height)
+{
+  GdkWindowObject *private;
+  
+  g_return_if_fail (GDK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
+
+  private = (GdkWindowObject *) window;
+
+  if (private->redirect)
+    gdk_window_remove_redirection (window);
+
+  if (width == -1 || height == -1)
+    {
+      gint w, h;
+      gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
+      if (width == -1)
+       width = w;
+      if (height == -1)
+       height = h;
+    }
+  
+  private->redirect = g_new0 (GdkWindowRedirect, 1);
+  private->redirect->redirected = private;
+  private->redirect->pixmap = g_object_ref (drawable);
+  private->redirect->src_x = src_x;
+  private->redirect->src_y = src_y;
+  private->redirect->dest_x = dest_x;
+  private->redirect->dest_y = dest_y;
+  private->redirect->width = width;
+  private->redirect->height = height;
+
+  apply_redirect_to_children (private, private->redirect);
+}
+
+static void
+window_get_size_rectangle (GdkWindow    *window,
+                           GdkRectangle *rect)
+{
+  rect->x = rect->y = 0;
+  gdk_drawable_get_size (GDK_DRAWABLE (window), &rect->width, &rect->height);
+}
+
+/* Calculates the real clipping region for a window, in window coordinates,
+ * taking into account other windows, gc clip region and gc clip mask.
+ */
+static GdkRegion *
+_gdk_window_calculate_full_clip_region (GdkWindow *window,
+                                       GdkWindow *base_window,
+                                       GdkGC *gc,
+                                       gboolean do_children,
+                                       gint *base_x_offset,
+                                       gint *base_y_offset)
+{
+  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
+  GdkRectangle visible_rect;
+  GdkRegion *real_clip_region, *tmpreg;
+  gint x_offset, y_offset;
+  GdkWindowObject *parentwin, *lastwin;
+
+  if (base_x_offset)
+    *base_x_offset = 0;
+  if (base_y_offset)
+    *base_y_offset = 0;
+  
+  if (!GDK_WINDOW_IS_MAPPED (window) || private->input_only)
+    return gdk_region_new ();
+
+  window_get_size_rectangle (window, &visible_rect);
+
+  /* windows that a redirection has ben setup for need to be considered
+   * fully visible, in order to avoid missing redirected paint ops
+   * anywhere in the window area.
+   */
+  if (private->redirect && private->redirect->redirected == private)
+    return gdk_region_rectangle (&visible_rect);
+
+  /* real_clip_region is in window coordinates */
+  real_clip_region = gdk_region_rectangle (&visible_rect);
+
+  x_offset = y_offset = 0;
+
+  lastwin = private;
+  if (do_children)
+    parentwin = lastwin;
+  else
+    parentwin = lastwin->parent;
+  
+  /* Remove the areas of all overlapping windows above parentwin in the hiearachy */
+  for (; parentwin != NULL && (parentwin == private || lastwin != (GdkWindowObject *)base_window);
+       lastwin = parentwin, parentwin = lastwin->parent)
+    {
+      GList *cur;
+      GdkRectangle real_clip_rect;
+      
+      if (parentwin != private)
+       {
+         x_offset += GDK_WINDOW_OBJECT (lastwin)->x;
+         y_offset += GDK_WINDOW_OBJECT (lastwin)->y;
+       }
+      
+      /* children is ordered in reverse stack order */
+      for (cur = GDK_WINDOW_OBJECT (parentwin)->children; cur && cur->data != lastwin; cur = cur->next)
+       {
+         GdkWindow *child = cur->data;
+         GdkWindowObject *child_private = (GdkWindowObject *)child;
+         
+         if (!GDK_WINDOW_IS_MAPPED (child) || child_private->input_only)
+           continue;
+         
+         window_get_size_rectangle (child, &visible_rect);
+         
+         /* Convert rect to "window" coords */
+         visible_rect.x += child_private->x - x_offset;
+         visible_rect.y += child_private->y - y_offset;
+         
+         /* This shortcut is really necessary for performance when there are a lot of windows */
+         gdk_region_get_clipbox (real_clip_region, &real_clip_rect);
+         if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
+             visible_rect.x + visible_rect.width <= real_clip_rect.x ||
+             visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
+             visible_rect.y + visible_rect.height <= real_clip_rect.y)
+           continue;
+         
+         tmpreg = gdk_region_rectangle (&visible_rect);
+         gdk_region_subtract (real_clip_region, tmpreg);
+         gdk_region_destroy (tmpreg);
+       }
+      
+    }
+
+  if (gc)
+    {
+      GdkRegion *clip_region = _gdk_gc_get_clip_region (gc);
+      
+      if (clip_region)
+       {
+         /* clip_region is relative to gc clip origin which is relative to the window */
+         /* offset it to window relative: */
+         tmpreg = gdk_region_copy (clip_region);
+         gdk_region_offset (real_clip_region,
+                            gc->clip_x_origin,
+                            gc->clip_y_origin);
+         /* Intersect it with window hierarchy cliprect: */
+         gdk_region_intersect (real_clip_region, tmpreg);
+         gdk_region_destroy (tmpreg);
+       }
+    }
+
+  if (base_x_offset)
+    *base_x_offset = x_offset;
+  if (base_y_offset)
+    *base_y_offset = y_offset;
+
+  return real_clip_region;
+}
+
+static void
+gdk_window_add_damage (GdkWindow *toplevel,
+                      GdkRegion *damaged_region)
+{
+  GdkDisplay *display;
+  GdkEvent event = { 0, };
+  event.expose.type = GDK_DAMAGE;
+  event.expose.window = toplevel;
+  event.expose.send_event = FALSE;
+  event.expose.region = damaged_region;
+  gdk_region_get_clipbox (event.expose.region, &event.expose.area);
+  display = gdk_drawable_get_display (event.expose.window);
+  _gdk_event_queue_append (display, gdk_event_copy (&event));
+}
+
+static void
+setup_redirect_clip (GdkWindow         *window,
+                    GdkGC             *gc,
+                    GdkWindowClipData *data)
+{
+  GdkWindowObject *private = (GdkWindowObject *)window;
+  GdkRegion *visible_region;
+  GdkRectangle dest_rect;
+  GdkRegion *tmpreg;
+  GdkWindow *toplevel;
+
+  data->old_region = _gdk_gc_get_clip_region (gc);
+  if (data->old_region) 
+    data->old_region = gdk_region_copy (data->old_region);
+
+  data->old_clip_x_origin = gc->clip_x_origin;
+  data->old_clip_y_origin = gc->clip_y_origin;
+
+  toplevel = GDK_WINDOW (private->redirect->redirected);
+  
+  /* Get the clip region for gc clip rect + window hierarchy in
+     window relative coords */
+  visible_region =
+    _gdk_window_calculate_full_clip_region (window, toplevel,
+                                           gc, TRUE,
+                                           &data->x_offset, 
+                                           &data->y_offset);
+
+  /* Compensate for the source pos/size */
+  data->x_offset -= private->redirect->src_x;
+  data->y_offset -= private->redirect->src_y;
+  dest_rect.x = -data->x_offset;
+  dest_rect.y = -data->y_offset;
+  dest_rect.width = private->redirect->width;
+  dest_rect.height = private->redirect->height;
+  tmpreg = gdk_region_rectangle (&dest_rect);
+  gdk_region_intersect (visible_region, tmpreg);
+  gdk_region_destroy (tmpreg);
+
+  /* Compensate for the dest pos */
+  data->x_offset += private->redirect->dest_x;
+  data->y_offset += private->redirect->dest_y;
+
+  gdk_gc_set_clip_region (gc, visible_region); /* This resets clip origin! */
+
+  /* offset clip and tiles from window coords to pixmaps coords */
+  gdk_gc_offset (gc, -data->x_offset, -data->y_offset);
+
+  /* Offset region to abs coords and add to damage */
+  gdk_region_offset (visible_region, data->x_offset, data->y_offset);
+  gdk_window_add_damage (toplevel, visible_region);
+  
+  gdk_region_destroy (visible_region);
+}
+
+static void
+reset_redirect_clip (GdkWindow *offscreen, GdkGC *gc, GdkWindowClipData *data)
+{
+  /* offset back */
+  gdk_gc_offset (gc, data->x_offset, data->y_offset);
+
+  /* reset old clip */
+  gdk_gc_set_clip_region (gc, data->old_region);
+  if (data->old_region)
+    gdk_region_destroy (data->old_region);
+  gdk_gc_set_clip_origin (gc, data->old_clip_x_origin, data->old_clip_y_origin);
+}
+
+static void
+gdk_window_redirect_free (GdkWindowRedirect *redirect)
+{
+  g_object_unref (redirect->pixmap);
+  g_free (redirect);
+}
+
 #define __GDK_WINDOW_C__
 #include "gdkaliasdef.c"
index f0ee7f5c8d2563b36ad85846f41bddfc6db53e4f..b29428a2a31fcf9f41252e68028a588b9f8aaedb 100644 (file)
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
 typedef struct _GdkGeometry           GdkGeometry;
 typedef struct _GdkWindowAttr        GdkWindowAttr;
 typedef struct _GdkPointerHooks              GdkPointerHooks;
+typedef struct _GdkWindowRedirect     GdkWindowRedirect;
 
 /* Classes of windows.
  *   InputOutput: Almost every window should be of this type. Such windows
@@ -300,6 +301,8 @@ struct _GdkWindowObject
   GdkEventMask event_mask;
 
   guint update_and_descendants_freeze_count;
+
+  GdkWindowRedirect *redirect;
 };
 
 struct _GdkWindowObjectClass
@@ -638,6 +641,13 @@ GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);
 
 GdkWindow *gdk_get_default_root_window (void);
 
+void gdk_window_redirect_to_drawable (GdkWindow *window,
+                                     GdkDrawable *drawable,
+                                     gint src_x, gint src_y,
+                                     gint dest_x, gint dest_y,
+                                     gint width, gint height);
+void gdk_window_remove_redirection   (GdkWindow *window);
+
 #ifndef GDK_DISABLE_DEPRECATED
 #define GDK_ROOT_PARENT()             (gdk_get_default_root_window ())
 #define gdk_window_get_size            gdk_drawable_get_size
index b316bc554cc41e2bacf5091cbf0b3d2c6cc5d526..b56f4f1d23d97a0aa6f6a5ebc468fc60c50352dd 100644 (file)
@@ -647,24 +647,10 @@ setup_toplevel_window (GdkWindow *window,
   ensure_sync_counter (window);
 }
 
-/**
- * gdk_window_new:
- * @parent: a #GdkWindow, or %NULL to create the window as a child of
- *   the default root window for the default display.
- * @attributes: attributes of the new window
- * @attributes_mask: mask indicating which fields in @attributes are valid
- * 
- * Creates a new #GdkWindow using the attributes from
- * @attributes. See #GdkWindowAttr and #GdkWindowAttributesType for
- * more details.  Note: to use this on displays other than the default
- * display, @parent must be specified.
- * 
- * Return value: the new #GdkWindow
- **/
 GdkWindow*
-gdk_window_new (GdkWindow     *parent,
-               GdkWindowAttr *attributes,
-               gint           attributes_mask)
+_gdk_window_new (GdkWindow     *parent,
+                GdkWindowAttr *attributes,
+                gint           attributes_mask)
 {
   GdkWindow *window;
   GdkWindowObject *private;
@@ -1843,22 +1829,11 @@ gdk_window_move_resize (GdkWindow *window,
     }
 }
 
-/**
- * gdk_window_reparent:
- * @window: a #GdkWindow
- * @new_parent: new parent to move @window into
- * @x: X location inside the new parent
- * @y: Y location inside the new parent
- *
- * Reparents @window into the given @new_parent. The window being
- * reparented will be unmapped as a side effect.
- * 
- **/
 void
-gdk_window_reparent (GdkWindow *window,
-                    GdkWindow *new_parent,
-                    gint       x,
-                    gint       y)
+_gdk_window_reparent (GdkWindow *window,
+                     GdkWindow *new_parent,
+                     gint       x,
+                     gint       y)
 {
   GdkWindowObject *window_private;
   GdkWindowObject *parent_private;
@@ -1866,16 +1841,6 @@ gdk_window_reparent (GdkWindow *window,
   GdkWindowImplX11 *impl;
   gboolean was_toplevel;
   
-  g_return_if_fail (GDK_IS_WINDOW (window));
-  g_return_if_fail (new_parent == NULL || GDK_IS_WINDOW (new_parent));
-  g_return_if_fail (GDK_WINDOW_TYPE (window) != GDK_WINDOW_ROOT);
-
-  if (GDK_WINDOW_DESTROYED (window) ||
-      (new_parent && GDK_WINDOW_DESTROYED (new_parent)))
-    {
-      return;
-    }
-  
   if (!new_parent)
     new_parent = gdk_screen_get_root_window (GDK_WINDOW_SCREEN (window));
 
index e8f386751b8016772f72353da21cc8b2f37b0534..241936185e6a7bf934513a4e8e81af59632141b0 100644 (file)
@@ -1529,6 +1529,7 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_VISIBILITY_NOTIFY:
     case GDK_WINDOW_STATE:
     case GDK_GRAB_BROKEN:
+    case GDK_DAMAGE:
       gtk_widget_event (event_widget, event);
       break;
 
index 78e425be718ec5ebf140d6e45ed8ad7247151292..1f4f9fbd09bd52c4730300ea60b9ab584dc0c6c6 100644 (file)
@@ -127,6 +127,7 @@ enum {
   QUERY_TOOLTIP,
   KEYNAV_FAILED,
   DRAG_FAILED,
+  DAMAGE_EVENT,
   LAST_SIGNAL
 };
 
@@ -1994,6 +1995,28 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
 
   /**
+   * GtkWidget::damage-event:
+   * @widget: the object which received the signal
+   * @event: the #GdkEventExpose event
+   *
+   * Emitted when a redirected window belonging to @widget gets drawn into.
+   * The region/area members of the event shows what area of the redirected
+   * drawable was drawn into.
+   *
+   * Returns: %TRUE to stop other handlers from being invoked for the event.
+   *   %FALSE to propagate the event further.
+   *
+   * Since: 2.16
+   */
+  widget_signals[DAMAGE_EVENT] =
+    g_signal_new ("damage_event",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST, 0,
+                 _gtk_boolean_handled_accumulator, NULL,
+                 _gtk_marshal_BOOLEAN__BOXED,
+                 G_TYPE_BOOLEAN, 1,
+                 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+/**
    * GtkWidget::grab-broken-event:
    * @widget: the object which received the signal
    * @event: the #GdkEventGrabBroken event
@@ -4667,6 +4690,9 @@ gtk_widget_event_internal (GtkWidget *widget,
        case GDK_GRAB_BROKEN:
          signal_num = GRAB_BROKEN;
          break;
+       case GDK_DAMAGE:
+         signal_num = DAMAGE_EVENT;
+         break;
        default:
          g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
          signal_num = -1;
@@ -8285,6 +8311,53 @@ gtk_widget_unref (GtkWidget *widget)
   g_object_unref ((GObject*) widget);
 }
 
+/**
+ * gtk_widget_get_snapshot:
+ * @widget: a #GtkWidget
+ *
+ * Creates a #GdkPixmap of the contents of the widget and its
+ * children. Works even if the widget is obscured.
+ * Note that the depth and visual of the resulting pixmap is dependent
+ * on the widget being snapshot and likely differs from those of a target
+ * widget displaying the pixmap. Use gdk_pixbuf_get_from_drawable()
+ * to convert the pixmap to a visual independant representation.
+ *
+ * Return value: #GdkPixmap of the widget
+ * Since: 2.16
+ **/
+GdkPixmap*
+gtk_widget_get_snapshot (GtkWidget *widget)
+{
+  GdkPixmap *pixmap;
+  int x, y;
+
+  if (!GTK_WIDGET_REALIZED (widget))
+    gtk_widget_realize (widget);
+
+  pixmap = gdk_pixmap_new (widget->window,
+                          widget->allocation.width,
+                          widget->allocation.height,
+                          gdk_drawable_get_depth (widget->window));
+  if (GTK_WIDGET_NO_WINDOW (widget))
+    {
+      x = widget->allocation.x;
+      y = widget->allocation.y;
+    }
+  else
+    x = y = 0;
+
+  gdk_window_redirect_to_drawable (widget->window,
+                                  pixmap,
+                                  x, y,
+                                  0, 0,
+                                  widget->allocation.width,
+                                  widget->allocation.height);
+  gtk_widget_queue_draw (widget);
+  gdk_window_process_updates (widget->window, TRUE);
+  gdk_window_remove_redirection (widget->window);
+
+  return pixmap;
+}
 
 /* style properties
  */
index d20d1f6d376a33d378d684dee8dcff60ab91918c..88e7dcaf296c05a4e43035e73f9a0d8f6ae57061 100644 (file)
@@ -416,6 +416,10 @@ struct _GtkWidgetClass
                                       gint        y,
                                       gboolean    keyboard_tooltip,
                                       GtkTooltip *tooltip);
+  /* Signals without a C default handler class slot:
+   * gboolean  (*damage_event) (GtkWidget      *widget,
+   *                             GdkEventExpose *event);
+   */
 
   /* Padding for future expansion */
   void (*_gtk_reserved5) (void);
@@ -610,6 +614,7 @@ GdkWindow *   gtk_widget_get_root_window (GtkWidget *widget);
 GtkSettings*  gtk_widget_get_settings    (GtkWidget *widget);
 GtkClipboard *gtk_widget_get_clipboard   (GtkWidget *widget,
                                          GdkAtom    selection);
+GdkPixmap *   gtk_widget_get_snapshot    (GtkWidget *widget);
 
 #ifndef GTK_DISABLE_DEPRECATED
 #define gtk_widget_set_visual(widget,visual)  ((void) 0)
index 1c0dde58e0e5edb7be3121199e31664f7e9aaef6..e0a47e9b45a772cf626b1c5748ed6d687b189dda 100644 (file)
@@ -12206,6 +12206,171 @@ create_properties (GtkWidget *widget)
   
 }
 
+struct SnapshotData {
+  GtkWidget *toplevel_button;
+  GtkWidget **window;
+  GdkCursor *cursor;
+  gboolean in_query;
+  gboolean is_toplevel;
+  gint handler;
+};
+
+static void
+destroy_snapshot_data (GtkWidget             *widget,
+                      struct SnapshotData *data)
+{
+  if (*data->window)
+    *data->window = NULL;
+  
+  if (data->cursor)
+    {
+      gdk_cursor_unref (data->cursor);
+      data->cursor = NULL;
+    }
+
+  if (data->handler)
+    {
+      g_signal_handler_disconnect (widget, data->handler);
+      data->handler = 0;
+    }
+
+  g_free (data);
+}
+
+static gint
+snapshot_widget_event (GtkWidget              *widget,
+                      GdkEvent        *event,
+                      struct SnapshotData *data)
+{
+  GtkWidget *res_widget = NULL;
+
+  if (!data->in_query)
+    return FALSE;
+  
+  if (event->type == GDK_BUTTON_RELEASE)
+    {
+      gtk_grab_remove (widget);
+      gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+                                 GDK_CURRENT_TIME);
+      
+      res_widget = find_widget_at_pointer (gtk_widget_get_display (widget));
+      if (data->is_toplevel && res_widget)
+       res_widget = gtk_widget_get_toplevel (res_widget);
+      if (res_widget)
+       {
+         GdkPixmap *pixmap;
+          GdkPixbuf *pixbuf = NULL;
+         GtkWidget *window, *image;
+
+         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+         pixmap = gtk_widget_get_snapshot (res_widget);
+          gtk_widget_realize (window);
+          if (gdk_drawable_get_depth (window->window) != gdk_drawable_get_depth (pixmap))
+            {
+              /* this branch is needed to convert ARGB -> RGB */
+              int width, height;
+              gdk_drawable_get_size (pixmap, &width, &height);
+              pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap,
+                                                     gtk_widget_get_colormap (res_widget),
+                                                     0, 0,
+                                                     0, 0,
+                                                     width, height);
+              image = gtk_image_new_from_pixbuf (pixbuf);
+            }
+          else
+            image = gtk_image_new_from_pixmap (pixmap, NULL);
+          g_object_unref (pixbuf);
+         gtk_container_add (GTK_CONTAINER (window), image);
+          g_object_unref (pixmap);
+         gtk_widget_show_all (window);
+       }
+
+      data->in_query = FALSE;
+    }
+  return FALSE;
+}
+
+
+static void
+snapshot_widget (GtkButton *button,
+                struct SnapshotData *data)
+{
+  gint failure;
+
+  g_signal_connect (button, "event",
+                   G_CALLBACK (snapshot_widget_event), data);
+
+  data->is_toplevel = GTK_WIDGET (button) == data->toplevel_button;
+  
+  if (!data->cursor)
+    data->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (button)),
+                                              GDK_TARGET);
+  
+  failure = gdk_pointer_grab (GTK_WIDGET (button)->window,
+                             TRUE,
+                             GDK_BUTTON_RELEASE_MASK,
+                             NULL,
+                             data->cursor,
+                             GDK_CURRENT_TIME);
+
+  gtk_grab_add (GTK_WIDGET (button));
+
+  data->in_query = TRUE;
+}
+
+static void
+create_snapshot (GtkWidget *widget)
+{
+  static GtkWidget *window = NULL;
+  GtkWidget *button;
+  GtkWidget *vbox;
+  struct SnapshotData *data;
+
+  data = g_new (struct SnapshotData, 1);
+  data->window = &window;
+  data->in_query = FALSE;
+  data->cursor = NULL;
+  data->handler = 0;
+
+  if (!window)
+    {
+      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+      gtk_window_set_screen (GTK_WINDOW (window),
+                            gtk_widget_get_screen (widget));      
+
+      data->handler = g_signal_connect (window, "destroy",
+                                       G_CALLBACK (destroy_snapshot_data),
+                                       data);
+
+      gtk_window_set_title (GTK_WINDOW (window), "test snapshot");
+      gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+      vbox = gtk_vbox_new (FALSE, 1);
+      gtk_container_add (GTK_CONTAINER (window), vbox);
+            
+      button = gtk_button_new_with_label ("Snapshot widget");
+      gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+      g_signal_connect (button, "clicked",
+                       G_CALLBACK (snapshot_widget),
+                       data);
+      
+      button = gtk_button_new_with_label ("Snapshot toplevel");
+      data->toplevel_button = button;
+      gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+      g_signal_connect (button, "clicked",
+                       G_CALLBACK (snapshot_widget),
+                       data);
+    }
+
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show_all (window);
+  else
+    gtk_widget_destroy (window);
+  
+}
+
+
 
 /*
  * Color Preview
@@ -13489,6 +13654,7 @@ struct {
   { "scrolled windows", create_scrolled_windows },
   { "shapes", create_shapes },
   { "size groups", create_size_groups },
+  { "snapshot", create_snapshot },
   { "spinbutton", create_spins },
   { "statusbar", create_statusbar },
   { "styles", create_styles },
@@ -13524,7 +13690,7 @@ create_main_window (void)
 
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_widget_set_name (window, "main window");
-  gtk_widget_set_uposition (window, 20, 20);
+  gtk_widget_set_uposition (window, 50, 20);
   gtk_window_set_default_size (GTK_WINDOW (window), -1, 400);
 
   geometry.min_width = -1;